<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" 
	xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
	xmlns:fo="http://www.w3.org/1999/XSL/Format" 
	xmlns:hbm="urn:nhibernate-mapping-2.2"
	xmlns:msxsl="urn:schemas-microsoft-com:xslt"
	xmlns:user="urn:xslt-helper"
	xmlns:helper="urn:helper">
	<xsl:import href="common.xslt"/>
	<xsl:output method="text" encoding="UTF-8"/>

	
	<xsl:template name="PropertyList">
		<xsl:param name="purpose"/>
		<xsl:param name="type-purpose" select="$purpose"/>
		<xsl:choose>
			<xsl:when test="$purpose='dto' or $purpose='interface'">
				<xsl:apply-templates mode="property" select="hbm:*[string(hbm:meta[@attribute='dto'])!='false']">
					<xsl:with-param name="purpose" select="$purpose"/>
					<xsl:with-param name="type-purpose" select="$type-purpose"/>
				</xsl:apply-templates>
			</xsl:when>
			<xsl:otherwise>
				<xsl:apply-templates mode="property" select="hbm:*">
					<xsl:with-param name="purpose" select="$purpose"/>
					<xsl:with-param name="type-purpose" select="$type-purpose"/>
				</xsl:apply-templates>
			</xsl:otherwise>
		</xsl:choose>
	</xsl:template>

	<xsl:template match="hbm:*" priority="-1" mode="property">
		<xsl:param name="purpose"/>
		<xsl:param name="type-purpose" select="$purpose"/>
		<xsl:call-template name="PropertyList">
			<xsl:with-param name="purpose" select="$purpose"/>
			<xsl:with-param name="type-purpose" select="$type-purpose"/>
		</xsl:call-template>
	</xsl:template>

	<xsl:template match="hbm:subclass" mode="property">		
	</xsl:template>

	<xsl:template match="hbm:component" mode="property">
		<xsl:param name="purpose"/>
		<xsl:param name="type-purpose" select="$purpose"/>
		<property name="{@name}" prop-type="entity" comment="{concat(hbm:meta[@attribute='comment'], hbm:comment)}">
			<xsl:attribute name="type">
				<xsl:call-template name="EntityType">
					<xsl:with-param name="type" select="@class"/>
					<xsl:with-param name="purpose" select="$type-purpose"/>
				</xsl:call-template>
			</xsl:attribute>
			<xsl:copy-of select="."/>
		</property>
	</xsl:template>

	<xsl:template match="hbm:parent" mode="property">
		<xsl:param name="purpose"/>
		<xsl:param name="type-purpose" select="$purpose"/>
		<property name="{@name}" prop-type="entity">
			<xsl:attribute name="type">
				<xsl:call-template name="EntityType">
					<xsl:with-param name="type" select="(ancestor::*[name()='class' or name='subclass'])[1]/@name"/>
					<xsl:with-param name="purpose" select="$type-purpose"/>
				</xsl:call-template>
			</xsl:attribute>
			<xsl:copy-of select="."/>
		</property>
	</xsl:template>

	<xsl:template match="hbm:property|hbm:id|hbm:version|hbm:timestamp|hbm:key-property" mode="property">
		<xsl:param name="purpose"/>
		<xsl:param name="type-purpose" select="$purpose"/>
		<property name="{@name}" prop-type="value">
			<xsl:attribute name="comment">
				<xsl:choose>
					<xsl:when test="name()='id' or name()='key-property'">Идентификатор записи</xsl:when>
					<xsl:otherwise>
						<xsl:value-of select="concat(hbm:meta[@attribute='comment'], hbm:comment)"/>
					</xsl:otherwise>
				</xsl:choose>
			</xsl:attribute>
			<xsl:attribute name="type">
				<xsl:call-template name="ValueType">
					<xsl:with-param name="type">
						<xsl:choose>
							<xsl:when test="name()='timestamp'">Timestamp</xsl:when>
							<xsl:otherwise>
								<xsl:value-of select="@type"/>
							</xsl:otherwise>
						</xsl:choose>
					</xsl:with-param>
					<xsl:with-param name="not-null" select="@not-null"/>
				</xsl:call-template>
			</xsl:attribute>
			<xsl:copy-of select="."/>
		</property>
	</xsl:template>

	<xsl:template match="hbm:many-to-one|hbm:one-to-one|hbm:key-many-to-one" mode="property">
		<xsl:param name="purpose"/>
		<xsl:param name="type-purpose" select="$purpose"/>
		<property name="{@name}" prop-type="entity">
			<xsl:attribute name="comment">
				<xsl:choose>
					<xsl:when test="name()='key-many-to-one'">Идентификатор записи</xsl:when>
					<xsl:otherwise>
						<xsl:value-of select="concat(hbm:meta[@attribute='comment'], hbm:comment)"/>
					</xsl:otherwise>
				</xsl:choose>
			</xsl:attribute>
			<xsl:attribute name="type">
				<xsl:call-template name="EntityType">
					<xsl:with-param name="type" select="@class"/>
					<xsl:with-param name="purpose" select="$type-purpose"/>
				</xsl:call-template>
			</xsl:attribute>
			<xsl:copy-of select="."/>
		</property>
	</xsl:template>

	<xsl:template match="hbm:bag|hbm:list|hbm:set|hbm:map|hbm:array" mode="property">
		<xsl:param name="purpose"/>
		<xsl:param name="type-purpose" select="$purpose"/>
		<xsl:variable name="type">
			<xsl:choose>
				<xsl:when test="hbm:element">
					<xsl:call-template name="ValueType">
						<xsl:with-param name="type" select="hbm:element/@type"/>
						<xsl:with-param name="not-null">true</xsl:with-param>
					</xsl:call-template>
				</xsl:when>
				<xsl:otherwise>
					<xsl:call-template name="EntityType">
						<xsl:with-param name="type" select="(hbm:one-to-many|hbm:many-to-many|hbm:composite-element)/@class"/>
						<xsl:with-param name="purpose" select="$type-purpose"/>
					</xsl:call-template>
				</xsl:otherwise>
			</xsl:choose>
		</xsl:variable>
		<property name="{@name}" prop-type="collection" comment="{concat(hbm:meta[@attribute='comment'], hbm:comment)}">
			<xsl:attribute name="type">
				<xsl:call-template name="CollectionType">
					<xsl:with-param name="purpose" select="$purpose"/>
					<xsl:with-param name="collection" select="name()"/>
					<xsl:with-param name="type" select="$type"/>
					<xsl:with-param name="index-type">
						<xsl:choose>
							<xsl:when test="hbm:index|hbm:map-key">
								<xsl:call-template name="ValueType">
									<xsl:with-param name="type" select="(hbm:index|hbm:map-key)/@type"/>
									<xsl:with-param name="not-null">true</xsl:with-param>
								</xsl:call-template>
							</xsl:when>
							<xsl:when test="hbm:composite-index|hbm:index-many-to-many|hbm:composite-map-key|hbm:map-key-many-to-many">
								<xsl:call-template name="EntityType">
									<xsl:with-param name="type" select="(hbm:composite-index|hbm:index-many-to-many|hbm:composite-map-key|hbm:map-key-many-to-many)/@class"/>
									<xsl:with-param name="purpose" select="$purpose"/>
								</xsl:call-template>
							</xsl:when>
							<xsl:otherwise/>
						</xsl:choose>
					</xsl:with-param>
				</xsl:call-template>
			</xsl:attribute>
			<xsl:attribute name="item-type">
				<xsl:value-of select="$type"/>
			</xsl:attribute>
			<xsl:attribute name="item-prop-type">
				<xsl:choose>
					<xsl:when test="hbm:element">value</xsl:when>
					<xsl:otherwise>entity</xsl:otherwise>
				</xsl:choose>
			</xsl:attribute>
			<xsl:attribute name="index-type">
				<xsl:choose>
					<xsl:when test="hbm:index|hbm:map-key">
						<xsl:call-template name="ValueType">
							<xsl:with-param name="type" select="(hbm:index|hbm:map-key)/@type"/>
							<xsl:with-param name="not-null">true</xsl:with-param>
						</xsl:call-template>
					</xsl:when>
					<xsl:when test="hbm:composite-index|hbm:index-many-to-many|hbm:composite-map-key|hbm:map-key-many-to-many">
						<xsl:call-template name="EntityType">
							<xsl:with-param name="type" select="(hbm:composite-index|hbm:index-many-to-many|hbm:composite-map-key|hbm:map-key-many-to-many)/@class"/>
							<xsl:with-param name="purpose" select="$purpose"/>
						</xsl:call-template>
					</xsl:when>
					<xsl:otherwise/>
				</xsl:choose>
			</xsl:attribute>
			<xsl:attribute name="index-prop-type">
				<xsl:choose>
					<xsl:when test="hbm:index|hbm:map-key">value</xsl:when>
					<xsl:otherwise>entity</xsl:otherwise>
				</xsl:choose>
			</xsl:attribute>
			<xsl:copy-of select="."/>
		</property>
	</xsl:template>

	<!-- конвертируем Value в нужный тип кода -->
	<xsl:template name="ValueType">
		<!-- тип, который надо преобразовать -->
		<xsl:param name="type"/>
		<!-- может быть null или нет -->
		<xsl:param name="not-null">true</xsl:param>
		<xsl:call-template name="type2type">
			<xsl:with-param name="type" select="$type"/>
			<xsl:with-param name="not-null" select="$not-null"/>
		</xsl:call-template>
	</xsl:template>

	<!-- конвертируем Entity в нужный тип кода -->
	<xsl:template name="EntityType">
		<!-- тип, который надо преобразовать -->
		<xsl:param name="type"/>
		<!-- для чего делаем коллекцию: dto, interface, class -->
		<xsl:param name="purpose"/>
		<xsl:choose>
			<xsl:when test="starts-with($type, $namespace)">
				<xsl:call-template name="EntityType">
					<xsl:with-param name="type" select="substring-after($type, concat($namespace, '.'))"/>
					<xsl:with-param name="purpose" select="$purpose"/>
				</xsl:call-template>
			</xsl:when>
			<xsl:when test="contains($type, ',')">
				<xsl:call-template name="EntityType">
					<xsl:with-param name="type" select="substring-before($type, ',')"/>
					<xsl:with-param name="purpose" select="$purpose"/>
				</xsl:call-template>
			</xsl:when>
			<xsl:when test="$purpose='dto'">
				<xsl:value-of select="concat($type, 'Dto')"/>
			</xsl:when>
			<xsl:when test="$purpose='interface'">
				<xsl:call-template name="InterfaceType">
					<xsl:with-param name="type" select="$type"/>
				</xsl:call-template>
			</xsl:when>
			<xsl:otherwise>
				<xsl:value-of select="$type"/>
			</xsl:otherwise>
		</xsl:choose>
	</xsl:template>

	<!-- конвертируем Entity в тип интерфейса -->
	<xsl:template name="InterfaceType">
		<!-- тип, который надо преобразовать -->
		<xsl:param name="type"/>
		<xsl:choose>
			<xsl:when test="contains($type, '.')">
				<xsl:value-of select="substring-before($type, '.')"/>
				<xsl:value-of select="string('.')"/>
				<xsl:call-template name="InterfaceType">
					<xsl:with-param name="type" select="substring-after($type, '.')"/>
				</xsl:call-template>
			</xsl:when>
			<xsl:otherwise>
				<xsl:value-of select="concat('I', $type)"/>
			</xsl:otherwise>
		</xsl:choose>
	</xsl:template>

	<!-- конвертируем Entity в коллекцию этого же типа -->
	<xsl:template name="CollectionType">
		<!-- тип из которого делать коллекцию -->
		<xsl:param name="type"/>
		<!-- тип ключа в словаре (используется только при $collection='map' -->
		<xsl:param name="index-type"/>
		<!-- для чего делаем коллекцию: dto, interface, class -->
		<xsl:param name="purpose"/>
		<!-- тип коллекций nhibernate: bag, set, list, map, array -->
		<xsl:param name="collection">bag</xsl:param>
		
		<xsl:choose>
			<xsl:when test="($purpose='dto' and $collection!='map')or $collection='array'">
				<!-- в Dto классах только массивы -->
				<xsl:value-of select="concat($type, '[]')"/>
			</xsl:when>
			<xsl:when test="$collection='set'">
				<xsl:value-of select="concat('ISet&lt;', $type, '&gt;')"/>
			</xsl:when>
			<xsl:when test="$collection='map' and $purpose='dto'">
				<xsl:value-of select="concat('Dictionary&lt;', $index-type, ', ', $type, '&gt;')"/>
			</xsl:when>
			<xsl:when test="$collection='map'">
				<xsl:value-of select="concat('IDictionary&lt;', $index-type, ', ', $type, '&gt;')"/>
			</xsl:when>
			<xsl:when test="$purpose='interface'">
				<!-- в интерфейсах только перечисления -->
				<xsl:value-of select="concat('IEnumerable&lt;', $type, '&gt;')"/>
			</xsl:when>
			<xsl:otherwise>
				<xsl:value-of select="concat('IList&lt;', $type, '&gt;')"/>				
			</xsl:otherwise>
		</xsl:choose>
	</xsl:template>
</xsl:stylesheet>
